using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

using Org.BouncyCastle.Bcpg.OpenPgp;
using Org.BouncyCastle.Security;
using Org.BouncyCastle.Bcpg;
using Org.BouncyCastle.Utilities.IO;
namespace Pbdms.Common.CryptoUtils
{
    public class Decrypter
    {
      
        #region verison 2

        public void DecryptFile( string outputfile,string filetodecrypt, PgpPrivateKey sKey)
        {
            Stream inputStream = null;
            Stream inputStreamtemp = null;

            try
            {
                inputStreamtemp = File.OpenRead(filetodecrypt);
                inputStream = PgpUtilities.GetDecoderStream(inputStreamtemp);


                PgpObjectFactory pgpF = new PgpObjectFactory(inputStream);
                PgpEncryptedDataList enc;

                PgpObject o = pgpF.NextPgpObject();
                //
                // the first object might be a PGP marker packet.
                //
                if (o is PgpEncryptedDataList)
                {
                    enc = (PgpEncryptedDataList)o;
                }
                else
                {
                    enc = (PgpEncryptedDataList)pgpF.NextPgpObject();

                }

                //
                // find the secret key
                //
                
                PgpPublicKeyEncryptedData pbe = null;


                foreach (PgpPublicKeyEncryptedData pked in enc.GetEncryptedDataObjects())
                {
                    //sKey = FindSecretKey(pgpSec, pked.KeyId, passwd);
                    


                    if (sKey != null)
                    {
                        pbe = pked;
                        break;
                    }
                    break;
                }
                Stream clear = pbe.GetDataStream(sKey);

                PgpObjectFactory plainFact = new PgpObjectFactory(clear);

                PgpCompressedData cData = (PgpCompressedData)plainFact.NextPgpObject();

                PgpObjectFactory pgpFact = new PgpObjectFactory(cData.GetDataStream());

                PgpObject message = pgpFact.NextPgpObject();
                clear.Close();
                if (message is PgpLiteralData)
                {
                    PgpLiteralData ld = (PgpLiteralData)message;
                    //Stream fOut = File.Create(outputfile + ld.FileName);
                    Stream fOut = File.Create(outputfile);
                    Stream unc = ld.GetInputStream();
                    Streams.PipeAll(unc, fOut);
                    fOut.Close();
                    unc.Close();
                }
                else if (message is PgpOnePassSignatureList)
                {
                    throw new Exception("encrypted message contains a signed message - not literal data.");
                }
                else
                {
                    throw new Exception("message is not a simple encrypted file - type unknown.");
                }

                if (pbe.IsIntegrityProtected())
                {
                    if (!pbe.Verify())
                    {
                        throw new Exception("message failed integrity check");
                    }
                    else
                    {
                        // throw new Exception("message integrity check passed");
                    }
                }
                else
                {
                    //throw new Exception("no message integrity check");
                }
            }
            catch (PgpException ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                inputStream.Close();
                inputStreamtemp.Close();

            }
        }
        public string DecryptMessage(string inputMsg, PgpPrivateKey sKey)
        {
            MemoryStream inputMem = null;
            Stream inputStream = null;
            MemoryStream outputMem = null;
            try
            {
                inputMem = new MemoryStream();
                System.Text.ASCIIEncoding encoding = new System.Text.ASCIIEncoding();
                byte[] data = encoding.GetBytes(inputMsg);
                int start = 0;
                while (start < data.Length)
                {
                    inputMem.WriteByte(data[start]);
                    start++;
                }
                inputMem.Seek(0, SeekOrigin.Begin);


                inputStream = PgpUtilities.GetDecoderStream(inputMem);


                PgpObjectFactory pgpF = new PgpObjectFactory(inputStream);
                PgpEncryptedDataList enc;

                PgpObject o = pgpF.NextPgpObject();
                //
                // the first object might be a PGP marker packet.
                //
                if (o is PgpEncryptedDataList)
                {
                    enc = (PgpEncryptedDataList)o;
                }
                else
                {
                    enc = (PgpEncryptedDataList)pgpF.NextPgpObject();

                }

                //
                // find the secret key
                //

                PgpPublicKeyEncryptedData pbe = null;


                foreach (PgpPublicKeyEncryptedData pked in enc.GetEncryptedDataObjects())
                {
                    //sKey = FindSecretKey(pgpSec, pked.KeyId, passwd);



                    if (sKey != null)
                    {
                        pbe = pked;
                        break;
                    }
                    break;
                }
                Stream clear = pbe.GetDataStream(sKey);

                PgpObjectFactory plainFact = new PgpObjectFactory(clear);

                PgpCompressedData cData = (PgpCompressedData)plainFact.NextPgpObject();

                PgpObjectFactory pgpFact = new PgpObjectFactory(cData.GetDataStream());

                PgpObject message = pgpFact.NextPgpObject();
                clear.Close();

               

                if (message is PgpLiteralData)
                {
                    PgpLiteralData ld = (PgpLiteralData)message;
                    //Stream fOut = File.Create(outputfile + ld.FileName);
                    outputMem= new MemoryStream();
                    Stream unc = ld.GetInputStream();
                    Streams.PipeAll(unc, outputMem);
           
                    unc.Close();
                }
                else if (message is PgpOnePassSignatureList)
                {
                    throw new Exception("encrypted message contains a signed message - not literal data.");
                }
                else
                {
                    throw new Exception("message is not a simple encrypted file - type unknown.");
                }

                if (pbe.IsIntegrityProtected())
                {
                    if (!pbe.Verify())
                    {
                        throw new Exception("message failed integrity check");
                       
                    }
                    else
                    {
                        outputMem.Seek(0, SeekOrigin.Begin);

                        int start2 = 0;
                        byte[] newBytes2 = new byte[outputMem.Length];
                        while (start2 < outputMem.Length)
                        {
                            newBytes2[start2] = (byte)outputMem.ReadByte();
                            start2++;
                        }
                        System.Text.ASCIIEncoding encoder = new System.Text.ASCIIEncoding();
                        string str = encoder.GetString(newBytes2);
                        return str;
                    }
                }
                else
                {
                    //throw new Exception("no message integrity check");
                }
            }
            catch (PgpException ex)
            {
                throw new Exception(ex.Message);
                
            }
            finally
            {

                //outputMem.Dispose();
                outputMem.Close();
                
                inputStream.Close();
                //inputMem.Dispose();
                inputMem.Close();

            }
            return null;
        }
        public MemoryStream DecryptBytes(MemoryStream bytesToDecrypt, PgpPrivateKey sKey)
        {
            //MemoryStream inputMem = null;
            Stream inputStream = null;
            MemoryStream outputMem = null;
            try
            {
               

                inputStream = PgpUtilities.GetDecoderStream(bytesToDecrypt);
               

                PgpObjectFactory pgpF = new PgpObjectFactory(inputStream);
                PgpEncryptedDataList enc;

                PgpObject o = pgpF.NextPgpObject();
                //
                // the first object might be a PGP marker packet.
                //
                if (o is PgpEncryptedDataList)
                {
                    enc = (PgpEncryptedDataList)o;
                }
                else
                {
                    enc = (PgpEncryptedDataList)pgpF.NextPgpObject();

                }

                //
                // find the secret key
                //

                PgpPublicKeyEncryptedData pbe = null;


                foreach (PgpPublicKeyEncryptedData pked in enc.GetEncryptedDataObjects())
                {
                    //sKey = FindSecretKey(pgpSec, pked.KeyId, passwd);



                    if (sKey != null)
                    {
                        pbe = pked;
                        break;
                    }
                    break;
                }
                Stream clear = pbe.GetDataStream(sKey);

                PgpObjectFactory plainFact = new PgpObjectFactory(clear);

                PgpCompressedData cData = (PgpCompressedData)plainFact.NextPgpObject();

                PgpObjectFactory pgpFact = new PgpObjectFactory(cData.GetDataStream());

                PgpObject message = pgpFact.NextPgpObject();
                clear.Close();



                if (message is PgpLiteralData)
                {
                    PgpLiteralData ld = (PgpLiteralData)message;
                    //Stream fOut = File.Create(outputfile + ld.FileName);
                    outputMem = new MemoryStream();
                    Stream unc = ld.GetInputStream();
                    Streams.PipeAll(unc, outputMem);

                    unc.Close();
                }
                else if (message is PgpOnePassSignatureList)
                {
                    throw new Exception("encrypted message contains a signed message - not literal data.");
                }
                else
                {
                    throw new Exception("message is not a simple encrypted file - type unknown.");
                }

                if (pbe.IsIntegrityProtected())
                {
                    if (!pbe.Verify())
                    {
                        throw new Exception("message failed integrity check");

                    }
                    else
                    {
                        outputMem.Seek(0, SeekOrigin.Begin);

                        return outputMem;
                    }
                }
                else
                {
                    //throw new Exception("no message integrity check");
                }
            }
            catch (PgpException ex)
            {
                throw new Exception(ex.Message);

            }
            finally
            {

                //outputMem.Dispose();
                //outputMem.Close();
                bytesToDecrypt.Close();
                inputStream.Close();
                //inputMem.Dispose();
                

            }
            return null;
        }
        #endregion
    }
}
